package com.zxj.camerademo.camera2;

import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.ImageFormat;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureFailure;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.TotalCaptureResult;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.Image;
import android.media.ImageReader;
import android.os.Handler;
import android.os.HandlerThread;
import android.support.annotation.NonNull;
import android.support.v4.content.ContextCompat;
import android.util.Log;
import android.util.Size;
import android.view.Surface;
import android.view.TextureView;
import android.widget.Toast;

import com.zxj.camerademo.utils.BitmapUtils;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class Camera2Helper {
    private static final String TAG = Camera2Helper.class.getSimpleName();
    private Activity mActivity;
    private TextureView mTextureView;
    private HandlerThread handlerThread = new HandlerThread("CameraThread");
    private Handler mCameraHandler;
    private CameraManager mCameraManager;
    private int mCameraFacing = CameraCharacteristics.LENS_FACING_BACK;         //默认使用后置摄像头
    private int mDisplayRotation;  //手机方向

    private ImageReader mImageReader= null;
    private CameraDevice mCameraDevice = null;
    private CameraCaptureSession mCameraCaptureSession = null;

    private String mCameraId = "0";
    private CameraCharacteristics mCameraCharacteristics;
    private boolean canTakePic = true;                                                       //是否可以拍照
    private int mCameraSensorOrientation = 0;                                            //摄像头方向
    private boolean canExchangeCamera = false;                                          //是否可以切换摄像头
    private static final int PREVIEW_WIDTH = 720;                                         //预览的宽度
    private static final int PREVIEW_HEIGHT = 1280;                                         //预览的高度
    private static final int SAVE_WIDTH = 720;                                         //保存图片的宽度
    private static final int SAVE_HEIGHT = 1280;                                         //保存图片的高度

    private Size mPreviewSize = new Size(PREVIEW_WIDTH, PREVIEW_HEIGHT);                      //预览大小
    private Size mSavePicSize = new Size(SAVE_WIDTH, SAVE_HEIGHT);                            //保存图片大小

    public Camera2Helper(Activity activity, TextureView textureView) {
        this.mActivity = activity;
        this.mTextureView = textureView;
        mDisplayRotation = mActivity.getWindowManager().getDefaultDisplay().getRotation();
        init();
    }

    private void init() {
        handlerThread.start();
        mCameraHandler = new Handler(handlerThread.getLooper());
        mTextureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
            @Override
            public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
                initCameraInfo();
            }

            @Override
            public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {

            }

            @Override
            public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
                releaseCamera();
                return true;
            }

            @Override
            public void onSurfaceTextureUpdated(SurfaceTexture surface) {

            }
        });
    }

    /**
     * 初始化
     */
    private void initCameraInfo() {
        mCameraManager = (CameraManager) mActivity.getSystemService(Context.CAMERA_SERVICE);
        String[] cameraIdList = null;
        try {
            cameraIdList = mCameraManager.getCameraIdList();
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
        if (cameraIdList == null || cameraIdList.length == 0) {
            Toast.makeText(mActivity, "没有可用相机", Toast.LENGTH_SHORT).show();
            return;
        }

        for (String id : cameraIdList) {
            CameraCharacteristics cameraCharacteristics = null;
            try {
                cameraCharacteristics = mCameraManager.getCameraCharacteristics(id);
            } catch (CameraAccessException e) {
                e.printStackTrace();
            }
            int facing = cameraCharacteristics.get(CameraCharacteristics.LENS_FACING);

            if (facing == mCameraFacing) {
                mCameraId = id;
                mCameraCharacteristics = cameraCharacteristics;
            }

            Log.e("Camera2Helper", "设备中的摄像头 " + id);
        }
        int supportLevel = mCameraCharacteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
        if (supportLevel == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) {
            Toast.makeText(mActivity, "相机硬件不支持新特性", Toast.LENGTH_SHORT).show();
        }

        //获取摄像头方向
        int mCameraSensorOrientation = mCameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
        //获取StreamConfigurationMap，它是管理摄像头支持的所有输出格式和尺寸
        StreamConfigurationMap configurationMap = mCameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);


        Size[] savePicSize = configurationMap.getOutputSizes(ImageFormat.JPEG);          //保存照片尺寸
        Size[] previewSize = configurationMap.getOutputSizes(SurfaceTexture.class); //预览尺寸

        boolean exchange = exchangeWidthAndHeight(mDisplayRotation, mCameraSensorOrientation);

        mSavePicSize = getBestSize(
                exchange ? mSavePicSize.getHeight() : mSavePicSize.getWidth(),
                exchange ? mSavePicSize.getWidth() : mSavePicSize.getHeight(),
                exchange ? mSavePicSize.getHeight() : mSavePicSize.getWidth(),
                exchange ? mSavePicSize.getWidth() : mSavePicSize.getHeight(),
                Arrays.asList(savePicSize));

        mPreviewSize = getBestSize(
                exchange ? mPreviewSize.getHeight() : mPreviewSize.getWidth(),
                exchange ? mPreviewSize.getWidth() : mPreviewSize.getHeight(),
                exchange ? mTextureView.getHeight() : mTextureView.getWidth(),
                exchange ? mTextureView.getWidth() : mTextureView.getHeight(),
                Arrays.asList(previewSize));

        mTextureView.getSurfaceTexture().setDefaultBufferSize(mPreviewSize.getWidth(),mPreviewSize.getHeight());

        Log.e(TAG,"预览最优尺寸 ："+mPreviewSize.getWidth()+" * "+mPreviewSize.getHeight()+", 比例  "+(float)mPreviewSize.getWidth() / mPreviewSize.getHeight());
        Log.e(TAG,"保存图片最优尺寸 ："+mSavePicSize.getWidth()+" * "+mSavePicSize.getHeight()+", 比例  "+(float)mSavePicSize.getWidth() / mSavePicSize.getHeight());

        mImageReader = ImageReader.newInstance(mSavePicSize.getWidth(), mSavePicSize.getHeight(), ImageFormat.JPEG, 1);
        mImageReader.setOnImageAvailableListener(onImageAvailableListener, mCameraHandler);

        openCamera();
    }

    /**
     * 根据提供的屏幕方向 [displayRotation] 和相机方向 [sensorOrientation] 返回是否需要交换宽高
     */
    private boolean exchangeWidthAndHeight(int displayRotation, int sensorOrientation) {
        boolean exchange = false;
        switch (displayRotation) {
            case Surface.ROTATION_0:
            case Surface.ROTATION_180:
                if (sensorOrientation == 90 || sensorOrientation == 270) {
                    exchange = true;
                }
                break;
            case Surface.ROTATION_90:
            case Surface.ROTATION_270:
                if (sensorOrientation == 0 || sensorOrientation == 180) {
                    exchange = true;
                } else {
                    Log.e(TAG, "Display rotation is invalid: " + displayRotation);
                }
                break;
        }

        Log.e(TAG, "屏幕方向  " + displayRotation);
        Log.e(TAG, "相机方向  " + sensorOrientation);
        return exchange;
    }

    /**
     * 根据提供的参数值返回与指定宽高相等或最接近的尺寸
     *
     * @param targetWidth  目标宽度
     * @param targetHeight
     * @param maxWidth
     * @param maxHeight
     * @param sizeList
     * @return
     */
    private Size getBestSize(int targetWidth, int targetHeight, int maxWidth, int maxHeight, List<Size> sizeList) {
        List<Size> bigEnough = new ArrayList<>();     //比指定宽高大的Size列表
        List<Size> notBigEnough = new ArrayList<>();  //比指定宽高小的Size列表

        for (Size size : sizeList) {
            //宽<=最大宽度  &&  高<=最大高度  &&  宽高比 == 目标值宽高比
            if (size.getWidth() <= maxWidth && size.getHeight() <= maxHeight
                    && size.getWidth() == size.getHeight() * targetWidth / targetHeight) {

                if (size.getWidth() >= targetWidth && size.getHeight() >= targetHeight)
                    bigEnough.add(size);
                else
                    notBigEnough.add(size);
            }
            if(flag) {
                flag = false;
                Log.e(TAG, "系统支持的尺寸: " + size.getWidth() + " * " + size.getHeight() + " ,  比例 ：" + (float) size.getWidth() / size.getHeight());
            }else {
                flag = true;
            }
        }

        Log.e(TAG, "最大尺寸 ：" + maxWidth + "* " + maxHeight + ", 比例 ：" + (float)targetWidth / targetHeight);
        Log.e(TAG, "目标尺寸 ：" + targetWidth + "* " + targetHeight + ", 比例 ：" + (float)targetWidth / targetHeight);

        //选择bigEnough中最小的值  或 notBigEnough中最大的值

        if (bigEnough.size() > 0) {
            return Collections.min(bigEnough, new CompareSizesByArea());
        } else if (notBigEnough.size() > 0) {
            return Collections.max(notBigEnough, new CompareSizesByArea());
        } else {
            return sizeList.get(0);
        }
    }
boolean flag;
    /**
     * 拍照
     */
    public void takePic() {
        if (mCameraDevice == null || !mTextureView.isAvailable() || !canTakePic) return;

        CaptureRequest.Builder captureRequestBuilder = null;
        try {
            captureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
            captureRequestBuilder.addTarget(mImageReader.getSurface());

            captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); // 自动对焦
            captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);     // 闪光灯
            captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, mCameraSensorOrientation);      //根据摄像头方向对保存的照片进行旋转，使其为"自然方向"
            if(mCameraCaptureSession != null) {
                mCameraCaptureSession.capture(captureRequestBuilder.build(), null, mCameraHandler);
//                mCameraCaptureSession.stopRepeating();
            }else {
                Toast.makeText(mActivity,"拍照异常！",Toast.LENGTH_SHORT).show();
            }

        } catch (CameraAccessException e) {
            e.printStackTrace();
        }

    }

    public void exchangeCamera() {
        if (mCameraDevice == null || !canExchangeCamera || !mTextureView.isAvailable()) return;
        if(mCameraFacing == CameraCharacteristics.LENS_FACING_FRONT){
            mCameraFacing = CameraCharacteristics.LENS_FACING_BACK;
        }else {
            mCameraFacing = CameraCharacteristics.LENS_FACING_FRONT;
        }
        mPreviewSize = new Size(PREVIEW_WIDTH, PREVIEW_HEIGHT); //重置预览大小
        releaseCamera();
        initCameraInfo();
    }

    public void releaseCamera() {
        if(mCameraCaptureSession != null){
            mCameraCaptureSession.close();
            mCameraCaptureSession = null;
        }

        if(mCameraDevice != null){
            mCameraDevice.close();
            mCameraDevice = null;
        }

        if(mImageReader != null){
            mImageReader.close();
            mImageReader = null;
        }

        canExchangeCamera = false;
    }

    public void releaseThread() {
        handlerThread.quitSafely();
    }

    private class CompareSizesByArea implements Comparator<Size> {

        @Override
        public int compare(Size size1, Size size2) {
            return java.lang.Long.signum(size1.getWidth() * size1.getHeight() - size2.getWidth() * size2.getHeight());
        }
    }

    private ImageReader.OnImageAvailableListener onImageAvailableListener = new ImageReader.OnImageAvailableListener() {
        @Override
        public void onImageAvailable(ImageReader reader) {
            Log.e("zuo","onImageAvailableListener------");
            Image image = reader.acquireLatestImage();
            ByteBuffer byteBuffer = image.getPlanes()[0].getBuffer();
            byte[] byteArray = new byte[byteBuffer.remaining()];
            byteBuffer.get(byteArray);
            reader.close();
            Log.e("zuo","onImageAvailableListener======");
            BitmapUtils.savePic(byteArray, mCameraSensorOrientation == 270, new OnSavePicState() {
                @Override
                public void onSuccess(final String savedPath, final long time) {
                    Log.e("zuo","onSuccess------");
                    mActivity.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            Toast.makeText(mActivity,"图片保存成功！ 保存路径："+savedPath+",耗时："+time,Toast.LENGTH_SHORT).show();
                        }
                    });
                }

                @Override
                public void onFailed(final String msg) {
                    Log.e("zuo","onFailed------"+msg);
                    mActivity.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            Toast.makeText(mActivity,"图片保存失败！ "+msg,Toast.LENGTH_SHORT).show();
                        }
                    });
                }
            });
        }
    };

    /**
     * 打开相机
     */
    private void openCamera(){
        if (ContextCompat.checkSelfPermission(mActivity, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
            Toast.makeText(mActivity,"没有相机权限！",Toast.LENGTH_SHORT).show();
            return;
        }
        try {
            mCameraManager.openCamera(mCameraId, new CameraDevice.StateCallback() {
                @Override
                public void onOpened(@NonNull CameraDevice camera) {
                    Log.d(TAG,"onOpened");
                    mCameraDevice = camera;
                    createCaptureSession(camera);
                }

                @Override
                public void onDisconnected(@NonNull CameraDevice camera) {
                    Log.d(TAG,"onDisconnected");
                }

                @Override
                public void onError(@NonNull CameraDevice camera, int error) {
                    Log.d(TAG,"onError:"+error);
                    Toast.makeText(mActivity,"打开相机失败！"+error,Toast.LENGTH_SHORT).show();
                }
            },mCameraHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    /**
     * 创建预览会话
     */
    private void createCaptureSession(CameraDevice cameraDevice) {
        CaptureRequest.Builder captureRequestBuilder = null;
        try {
            captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
            Surface surface = new Surface(mTextureView.getSurfaceTexture());
            captureRequestBuilder.addTarget(surface);  // 将CaptureRequest的构建器与Surface对象绑定在一起
            captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);      // 闪光灯
            captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); // 自动对焦

            final CaptureRequest.Builder finalCaptureRequestBuilder = captureRequestBuilder;

            // 为相机预览，创建一个CameraCaptureSession对象
            cameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()), new CameraCaptureSession.StateCallback() {
                @Override
                public void onConfigured( @NonNull CameraCaptureSession session) {
                    mCameraCaptureSession = session;
                    try {
                        session.setRepeatingRequest(finalCaptureRequestBuilder.build(), mCaptureCallBack, mCameraHandler);
                    } catch (CameraAccessException e) {
                        e.printStackTrace();
                    }
                }

                @Override
                public void onConfigureFailed( @NonNull CameraCaptureSession session) {
                    Toast.makeText(mActivity,"开启预览会话失败！",Toast.LENGTH_SHORT).show();
                }
            },mCameraHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    private CameraCaptureSession.CaptureCallback mCaptureCallBack = new CameraCaptureSession.CaptureCallback() {

        @Override
        public void onCaptureCompleted( @NonNull CameraCaptureSession session, @NonNull CaptureRequest request,@NonNull TotalCaptureResult result) {
            super.onCaptureCompleted(session, request, result);
            canExchangeCamera = true;
            canTakePic = true;
        }

        @Override
        public void onCaptureFailed( @NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureFailure failure) {
            super.onCaptureFailed(session, request, failure);
            Log.d(TAG,"onCaptureFailed");
            Toast.makeText(mActivity,"开启预览失败！",Toast.LENGTH_SHORT).show();
        }
    };
}
